001 /* 002 * CSHApplication.java 003 * 004 * Created on July 10, 2003, 11:22 AM 005 * 006 * This file is part of the STAR Scheduler. 007 * Copyright (c) 2002-2003 STAR Collaboration - Brookhaven National Laboratory 008 * 009 * STAR Scheduler is free software; you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as published by 011 * the Free Software Foundation; either version 2 of the License, or 012 * (at your option) any later version. 013 * 014 * STAR Scheduler is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public License 020 * along with STAR Scheduler; if not, write to the Free Software 021 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 022 */ 023 package gov.bnl.star.offline.scheduler.lsf; 024 025 import gov.bnl.star.offline.scheduler.*; 026 import gov.bnl.star.offline.scheduler.catalog.PhysicalFile; 027 import gov.bnl.star.offline.scheduler.util.FileListToolkit; 028 import gov.bnl.star.offline.scheduler.util.FilesystemToolkit; 029 import gov.bnl.star.offline.scheduler.util.VariablesToolkit; 030 031 import java.io.File; 032 import java.io.FileOutputStream; 033 import java.io.PrintStream; 034 035 import java.util.*; 036 import java.util.logging.Level; 037 import java.util.logging.Logger; 038 039 040 /** Application module for csh. 041 * <p> 042 * This module defines the interface of a csh task, and prepare the task 043 * information in the following environment variables: 044 * <p> 045 * $JOBID - the unique job id given by the scheduler<br> 046 * $FILESLIST - the file name of a text file containing the file list assigned to 047 * the job<br> 048 * $INPUTFILECOUNT - the number of files assigned to the job<br> 049 * $INPUTFILExx - the input files associated to the job<br> 050 * <p> 051 * @author Gabriele Carcassi, Jerome Lauret 052 * @version 1.0 2002/12/26 053 */ 054 public class CSHApplication { 055 static private Logger log = Logger.getLogger(CSHApplication.class.getName()); 056 private Request request; 057 private Job job; 058 private String scratchDir; 059 private String submissionCommand; 060 private Map variables; 061 062 /** Holds value of property recurseCopy. */ 063 private boolean recurseCopy = false; 064 065 /** Holds the value for the property of EnvVariableLimit */ 066 private int EnvVariableLimit; 067 068 /** Holds value of property copyScript. */ 069 private String copyScript; 070 071 /** Holds value of property storageScript. */ 072 private String storageScript; 073 074 /** Holds value of property registerScript. */ 075 private String registerScript; 076 077 /** Creates a new instance of CSHApplication */ 078 public CSHApplication() { 079 } 080 081 /** Returns the CSH application module. In the future, the application should 082 * be taken directly from the component library. This method is provided 083 * for compatibility with the old framework. 084 * @return the CSH application module 085 */ 086 public static CSHApplication getInstance() { 087 return (CSHApplication) ComponentLibrary.getInstance().getComponent("CSHApplication"); 088 } 089 090 /** Prepares the task, by creating the script. */ 091 public void prepareJob() { 092 try { 093 PrintStream inputFileList = new PrintStream(new FileOutputStream( 094 new File(getInputFileListName()))); 095 createInputFileList(inputFileList); 096 } catch (Exception e) { 097 log.log(Level.SEVERE, "Couldn't create the file list", e); 098 throw new RuntimeException("Couldn't create the file list " + 099 getInputFileListName() + ": " + e.getMessage()); 100 } 101 102 try { 103 PrintStream cshScript = new PrintStream(new FileOutputStream( 104 new File(getCSHScriptName()))); 105 createCSHScript(cshScript); 106 makeScriptFileExecutable(getCSHScriptName()); 107 } catch (Exception e) { 108 log.log(Level.SEVERE, "Couldn't create the script", e); 109 throw new RuntimeException("Couldn't create the script " + 110 getCSHScriptName() + ": " + e.getMessage()); 111 } 112 } 113 114 /** Returns the command line to execute the task set by <CODE>setJob</CODE>. 115 * @return Command line to execute the task 116 */ 117 public String getCommandLine() { 118 return getCSHScriptName(); 119 } 120 121 /* Calls chmod to make the script executable. */ 122 private void makeScriptFileExecutable(String fileName) { 123 // Hack to make the Unit tests work on windows. 124 // chmod doesn't exist on Windows (if you don't have cygwin) 125 if (System.getProperty("os.name").startsWith("Win")) return; 126 127 try { 128 String chmod = "chmod +x " + fileName; 129 log.info("Executing \"" + chmod + "\""); 130 131 java.lang.Process shell = Runtime.getRuntime().exec(chmod); 132 shell.waitFor(); 133 } catch (Exception e) { 134 log.log(Level.SEVERE, "Couldn't make the script executable", e); 135 throw new RuntimeException("Couldn't make the script " + fileName + 136 " executable", e); 137 } 138 } 139 140 /** Sets the task the application will have to prepare. 141 * @param request the request that originated the task 142 * @param job the job to be executed 143 */ 144 public void setJob(Request request, Job job) { 145 this.request = request; 146 this.job = job; 147 scratchDir = null; 148 submissionCommand = null; 149 variables = null; 150 } 151 152 /** Sets the scratch directory for the temporary output files of the job. 153 * @param scratchDir the temporary output directory 154 */ 155 public void setScratchDir(String scratchDir) { 156 this.scratchDir = scratchDir; 157 } 158 159 /** Sets the submittion command used to submit the job. This will be included in the 160 * script for resubmission. 161 * @param submissionCommand the command line to submit the job to the batch system 162 */ 163 public void setSubmissionCommand(String submissionCommand) { 164 this.submissionCommand = submissionCommand; 165 } 166 167 /** Generates the csh script to be submitted through LSF. 168 * @param out the stream on which to print the script 169 */ 170 private void createCSHScript(PrintStream out) { 171 // Sets the shell that will interpret the script 172 173 ////////////test area//////////////// 174 Map config = (Map) ComponentLibrary.getInstance().getComponent("registerScript"); 175 176 out.println("#!/bin/csh"); 177 178 out.println("# ------------------- "); 179 out.println("# Script generated at " + new Date() + 180 " by the STAR scheduler and submitted with"); 181 out.println("# " + submissionCommand); 182 out.println("# ------------------- "); 183 184 Map env = getEnvironmentVariables(); 185 186 Iterator variables = env.keySet().iterator(); 187 Iterator FilesNameVariable = env.keySet().iterator(); 188 189 // Sets all the environment variable. 190 out.println(); 191 out.println("# Preparing environment variables"); 192 193 String varName, varValue; 194 195 196 int counter=0; 197 String padding=""; 198 while (variables.hasNext()) { //First pass prints all the environment variables that do not start with “INPUTFILE” 199 varName = (String) variables.next(); 200 varValue = (String) env.get(varName); 201 if((! varName.startsWith("INPUTFILE")) || (varName.matches("INPUTFILECOUNT"))){ 202 out.println(padding + "setenv " + varName + " " + varValue); 203 } 204 } 205 206 while (FilesNameVariable.hasNext()) { //Second pass prints all the environment variables that start with “INPUTFILE” 207 varName = (String) FilesNameVariable.next(); 208 varValue = (String) env.get(varName); 209 if(varName.startsWith("INPUTFILE") && (! varName.matches("INPUTFILECOUNT"))){ 210 if (counter == EnvVariableLimit){ 211 out.println("#"); 212 out.println("# Note: The configuration requested a limitation of the"); 213 out.println("# number of INPUTFILE(n) environemnt variables at "+EnvVariableLimit); 214 out.println("# The rest of the variables will be commented."); 215 out.println("#"); 216 padding = "# "; 217 } 218 counter++; 219 out.println(padding + "setenv " + varName + " " + varValue); 220 } 221 } 222 223 // Creates the scratch directory 224 out.println(); 225 out.println("# Creating the scratch directory, return failure status"); 226 out.println("mkdir -p $SCRATCH"); 227 out.println("set STS=$status"); 228 out.println("if (! -d $SCRATCH) then"); 229 out.println(" echo \"Scheduler:: Failed to create $SCRATCH on $HOST\""); 230 out.println(" exit $STS"); 231 out.println("endif"); 232 233 // Adds the command to be executed 234 out.println(); 235 out.println("###################################################"); 236 //out.println("/bin/csh -s ___EOD"+job.getJobID()+"__"); 237 out.println("# User command BEGIN ----------------------------->"); 238 239 out.println(request.getCommand()); 240 241 out.println("# <------------------------------User command BEGIN"); 242 //out.println("___EOD"+job.getJobID()+"__"); 243 out.println("###################################################"); 244 245 // Copy output files 246 out.println(); 247 out.println("# Copy output files (if any where specified)"); 248 249 out.print(generateScriptFragment(request.getOutputList())); 250 251 // Delete the scratch directory 252 out.println(); 253 out.println("# Delete the scratch directory"); 254 out.println("/bin/rm -fr $SCRATCH"); 255 } 256 257 String generateScriptFragment(List outputList) { 258 StringBuffer buffer = new StringBuffer(); 259 for (int nOutput = 0; nOutput < outputList.size(); nOutput++) { 260 OutputFile output = (OutputFile) outputList.get(nOutput); 261 if (output.getActionList().size() != 0) { 262 buffer.append("setenv OUTPUTFILE").append(nOutput).append(" file:/$SCRATCH/"). 263 append(output.getFromScratch()).append("\n"); 264 for (int nOutputAction = 0; nOutputAction < output.getActionList().size(); nOutputAction++) { 265 if (output.getActionList().get(nOutputAction) instanceof OutputCopyAction) { 266 buffer.append(generateScriptFragment(nOutput, (OutputCopyAction) output.getActionList().get(nOutputAction))); 267 } else if (output.getActionList().get(nOutputAction) instanceof OutputRegisterAction) { 268 buffer.append(generateScriptFragment(nOutput, (OutputRegisterAction) output.getActionList().get(nOutputAction))); 269 } else { 270 log.severe("Unsupported OutputAction time found: " + output.getActionList().get(nOutputAction).getClass().getName()); 271 throw new RuntimeException("Unsupported OutputAction time found"); 272 } 273 } 274 } else { 275 if (recurseCopy) { 276 buffer.append("/bin/cp -r $SCRATCH/").append(output.getFromScratch()).append(" "). 277 append(output.getToURL().getPath()).append("\n"); 278 } else { 279 buffer.append("/bin/cp $SCRATCH/").append(output.getFromScratch()).append(" "). 280 append(output.getToURL().getPath()).append("\n"); 281 } 282 } 283 } 284 return buffer.toString(); 285 } 286 287 String generateScriptFragment(int nOutput, OutputCopyAction action) { 288 StringBuffer fragment = new StringBuffer(); 289 if (action.getFileRef() != null) { 290 if (action.getStorageService() != null) { 291 fragment.append("setenv OUTPUTFILE").append(nOutput).append('_'). 292 append(action.getFileRef()).append(" `").append(getStorageScript()). 293 append(" \"").append(action.getStorageService()).append("\" `"). 294 append(action.getURI().getPath()).append("\n"); 295 296 } else { 297 fragment.append("setenv OUTPUTFILE").append(nOutput).append('_'). 298 append(action.getFileRef()).append(" "). 299 append(action.getURI()).append("\n"); 300 } 301 fragment.append(getCopyScript()).append(" $OUTPUTFILE").append(nOutput). 302 append(" $OUTPUTFILE").append(nOutput).append('_').append(action.getFileRef()). 303 append("\n"); 304 } else { 305 fragment.append(getCopyScript()).append(" $OUTPUTFILE").append(nOutput); 306 if (action.getStorageService() != null) { 307 fragment.append(" `").append(getStorageScript()). 308 append(" \"").append(action.getStorageService()).append("\" `"). 309 append(action.getURI().getPath()).append("\n"); 310 } else { 311 fragment.append(" ").append(action.getURI()).append("\n"); 312 } 313 } 314 return fragment.toString(); 315 } 316 317 String generateScriptFragment(int nOutput, OutputRegisterAction action) { 318 StringBuffer fragment = new StringBuffer(); 319 fragment.append(getRegisterScript()).append(" $OUTPUTFILE").append(nOutput); 320 if (action.getFileRef() != null) { 321 fragment.append('_'). append(action.getFileRef()); 322 } 323 int queryStart = action.getURI().getSchemeSpecificPart().indexOf('?'); 324 queryStart++; 325 fragment.append(" '"). 326 append(action.getURI().getSchemeSpecificPart().substring(queryStart)).append("'\n"); 327 return fragment.toString(); 328 } 329 330 /** Generates the input file list. It consists of full path names, one line for each 331 * one. 332 * @param out the stream on which to print the file list 333 */ 334 private void createInputFileList(PrintStream out) { 335 if ("paths".equals(request.getFileListType())) { 336 FileListToolkit.createPathsFileList(out, job.getInput()); 337 } else if ("rootd".equals(request.getFileListType())) { 338 FileListToolkit.createRootdFileList(out, job.getInput()); 339 } 340 } 341 342 /** Returns the name for the csh script. 343 * @return the csh script name 344 */ 345 public String getCSHScriptName() { 346 return FilesystemToolkit.getCurrentDirectory() + "/sched" + 347 job.getJobID() + ".csh"; 348 } 349 350 /** Returns the name for the input file list file. 351 * @return the input file list name 352 */ 353 public String getInputFileListName() { 354 return "sched" + job.getJobID() + ".list"; 355 } 356 357 358 private Map getEnvironmentVariables() { 359 if (variables != null) { 360 return variables; 361 } 362 363 variables = new Hashtable(); 364 365 variables = new TreeMap(job.getEnv()); 366 variables.put("JOBID", job.getJobID()); 367 variables.put("REQUESTID", job.getRequestID()); 368 variables.put("PROCESSID", job.getProcessID()); 369 370 // FIXME: scratch dir should be passed in a nicer way 371 variables.put("SCRATCH", scratchDir); 372 variables.put("FILELIST", getInputFileListName()); 373 374 List inputList = job.getInput(); 375 variables.put("INPUTFILECOUNT", Integer.toString(inputList.size())); 376 377 for (int nFile = 0; nFile < inputList.size(); nFile++) { 378 PhysicalFile file = (PhysicalFile) inputList.get(nFile); 379 variables.put("INPUTFILE" + nFile, 380 file.getPath() + "/" + file.getFilename()); 381 } 382 383 384 //If there is only one input file per csh make an Environment Variable called FILEBASENAME 385 if(inputList.size() == 1){ 386 PhysicalFile file = (PhysicalFile) inputList.get(0); 387 if(! (file.getFilename().indexOf(".") == -1)) 388 variables.put("FILEBASENAME",file.getFilename().substring(0,file.getFilename().indexOf("."))); 389 else 390 variables.put("FILEBASENAME",file.getFilename()); 391 } 392 else{ //All other times FILEBASENAME will be set to this value 393 variables.put("FILEBASENAME","FILEBASENAME.NOT.INITIALIZED." + job.getJobID()); 394 } 395 396 return variables; 397 } 398 399 /** Returns the file for standard input redirection. 400 * @return stdin file 401 */ 402 public String getStdin() { 403 if (job.getStdin() != null) { 404 return VariablesToolkit.substituteVariables(job.getStdin().getPath(), 405 CSHApplication.getInstance().getEnvironmentVariables()); 406 } 407 408 return null; 409 } 410 411 /** Returns the file for standard output redirection. 412 * @return stdout file 413 */ 414 public String getStdout() { 415 if (job.getStdout() != null) { 416 if (job.getStdout() == Request.discard) { 417 return "/dev/null"; 418 } 419 420 return VariablesToolkit.substituteVariables(job.getStdout().getPath(), 421 CSHApplication.getInstance().getEnvironmentVariables()); 422 } 423 424 return null; 425 } 426 427 /** Returns the file for standard error redirection. 428 * @return stderr file 429 */ 430 public String getStderr() { 431 if (job.getStderr() != null) { 432 if (job.getStderr() == Request.discard) { 433 return "/dev/null"; 434 } 435 436 return VariablesToolkit.substituteVariables(job.getStderr().getPath(), 437 CSHApplication.getInstance().getEnvironmentVariables()); 438 } 439 440 return null; 441 } 442 443 /** Returns the job name to be assigned to the batch system. 444 * @return the job name to be used by the batch system 445 */ 446 public String getJobName() { 447 return request.getName(); 448 } 449 450 /** Getter for property recurseCopy. 451 * @return Value of property recurseCopy. 452 * 453 */ 454 public boolean isRecurseCopy() { 455 return this.recurseCopy; 456 } 457 458 /** Setter for property recurseCopy. 459 * @param recurseCopy New value of property recurseCopy. 460 * 461 */ 462 public void setRecurseCopy(boolean recurseCopy) { 463 this.recurseCopy = recurseCopy; 464 } 465 466 467 /** Getter for property EnvVariableLimit. 468 * @return Value of property EnvVariableLimit. 469 * 470 */ 471 public int getEnvVariableLimit() { 472 return this.EnvVariableLimit; 473 } 474 475 /** Setter for property EnvVariableLimit. 476 * @param EnvVariableLimit New value of property EnvVariableLimit. 477 * 478 */ 479 public void setEnvVariableLimit(int EnvVariableLimit) { 480 this.EnvVariableLimit = EnvVariableLimit; 481 } 482 483 484 /** Getter for property copyScript. 485 * @return Value of property copyScript. 486 * 487 */ 488 public String getCopyScript() { 489 return this.copyScript; 490 } 491 492 /** Setter for property copyScript. 493 * @param copyScript New value of property copyScript. 494 * 495 */ 496 public void setCopyScript(String copyScript) { 497 this.copyScript = copyScript; 498 } 499 500 /** Getter for property storageScript. 501 * @return Value of property storageScript. 502 * 503 */ 504 public String getStorageScript() { 505 return this.storageScript; 506 } 507 508 /** Setter for property storageScript. 509 * @param storageScript New value of property storageScript. 510 * 511 */ 512 public void setStorageScript(String storageScript) { 513 this.storageScript = storageScript; 514 } 515 516 /** Getter for property registerScript. 517 * @return Value of property registerScript. 518 * 519 */ 520 public String getRegisterScript() { 521 return this.registerScript; 522 } 523 524 /** Setter for property registerScript. 525 * @param registerScript New value of property registerScript. 526 * 527 */ 528 public void setRegisterScript(String registerScript) { 529 this.registerScript = registerScript; 530 } 531 532 }